local skynet = require "skynet"
require "skynet.manager"
local GAMECMD = require "game_proto"
local CMD = require "game_proto"
require "ntmj"
require "chairaction"
local MJCONST =  require "const"
local TABLECONST = MJCONST.TABLECONST
local PAICONST = MJCONST.PAICONST
local WIKTYPE = MJCONST.WIKTYPE
local TableConfig = {FanJiangNum = 1, HasXiPai = true, MaiZhuang = true}

local Seat = require "Seat"
local GameLogic = require "GameLogic"

function send_data(addr,msg)
    skynet.send(math.floor(addr),"lua","send_data",msg)
end

local TableLogic = GameLogic:extend()

local FANWAIFAN = {QINGYISE=0x0001,HAIDIHU=0x0002,HAIDIPAO=0x0004,GANGHUA=0x0008,GANGPAO=0x0010,QUANQIUREN=0x0020,QIANGGANGHU=0x0040,TIANHU=0x0080,DIHU=0x0100,MENQINIG=0x0200,QUANQIURENDIANPAO=0x0400,SHISANYAO=0x0800,ZIYISE=0x1000}

local MainCmdId = CMD.Main_ClientAndGameSvr_TableModle

TableLogic.CanChi = false   --是否支持吃

local nGameJuIndex = 0    --第几局

local GameState = {ready=0, play=1, conclude=3}  --开始前，游戏中，结算中

HuPaiResult = {}
function HuPaiResult:New(obj)
    obj = obj or {}
    setmetatable(obj, self)
    self.__index = self
    return obj
end

function HuPaiResult:GetPackString()
    local bufData = string.pack('B', self.CardData or 0)
    for i = 1, TABLECONST.FULL_PLAYER do           --每个人是否胡
        local tHu = {[true] = 1, [false] = 0}
        bufData = bufData..string.char(tHu[self.bHu[i]] or 0)
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人的分数
        bufData = bufData..string.pack('i4', self.gameScoreJu[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人的胡数
        bufData = bufData..string.pack('i4', self.huShuJu[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人手牌的数量
        bufData = bufData..string.char(#self.standCard[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人的手牌
        for j = 1, TABLECONST.MAX_COUNT do
            local standPai = self.standCard[i][j]
            bufData = bufData..string.char(standPai or 0)
        end
    end
    for i = 1, TABLECONST.FULL_PLAYER do
        local len = #self.huPaiMsg[i]
        if len > 0 then 
            local len = string.len(self.huPaiMsg[i])
            bufData = bufData..self.huPaiMsg[i]
            bufData = bufData..BufTool.WriteOffset(256 - len)
        else bufData = bufData..BufTool.WriteOffset(256) end
    end
    return bufData
end


function TableLogic:initialize(room)
    TableLogic.meta.super.initialize(self,room)
    self.chairAddr={}
	self.chairAct={}
	self.chairIndex={}
	self.PlayerNum=3
	self.Banker=0
	self.CurUserId=0
	self.LeftCardCount=TABLECONST.PAI_TOTAL
	self.PingHuZiMo=false
end

function TableLogic:InitGameData()
    for _,seat in pairs(self.m_pChairs) do
        seat.chairAction = {UserChairID=seat.m_wChairId, tabCbCardIndex = {},tabCbOutCard = {}, tabWeaveItem = {}, tabUserAction = {}, tabTingCardData={} }
		--self.chairAct[seat.m_wChairId] = ChairAction:New(seat.chairAction)
		--self.chairAct[seat.m_wChairId]:Init()
	end
    self:InitChair()
	self:RegisterFun()
end

function TableLogic:InitChair()
    for i = 1, #self.chairIndex do
        local index = self.chairIndex[i]
        self.chairAct[index] = ChairAction:New(self.m_pChairs[index-1].chairAction)
        self.chairAct[index]:Init()
    end
end

function TableLogic:SetTableData(Table, nMaxPlayerCount, nDiFen, nMa, nFangPaoOrZiMo, nDianPaoMaOrZiMoMa, nKeQiangGang, externData)
    local cpDes = TableLogic:GetRoomInfo(externData)
    self.PlayerNum = 3--nMaxPlayerCount 
    local strMakeRoomMsg = '南通长牌 '..cpDes
    TableLogic.DiFen = nDiFen
    self:RegisterFun() 
    return strMakeRoomMsg
end

function TableLogic:GetRoomInfo(externData)
    skynet.error('TableLogic SetTableData, len of externData is ', string.len(externData))
    local jiang, xi, difen, maizhuang, fending = string.unpack('iiiii', externData)
    print(string.format("%s,%s,%s,%s,%s",jiang or 0, xi or 0, difen or 0, maizhuang or 0, fending or 0))
    TableConfig.FanJiangNum = jiang
    TableConfig.HasXiPai = (xi == 1)
    TableConfig.MaiZhuang = (maizhuang == 1)
    TableConfig.FengDing = (fending or 1)
    if not TableConfig.HasXiPai then TABLECONST.PAI_TOTAL = TABLECONST.PAI_TOTAL - 5 end  --没有喜牌
    print(string.format('jiang is %d, xi is %d', jiang, xi)) --单双将(1,2),喜(1,2),底分(1),买庄(1,0)，封顶(1,2,3)
    local jiangDes = {[1] = '单将', [2] = '双将'}
    local xiDes = {[1] = '带喜牌', [2] = '不带喜牌'}
    local difenDes = {[1] = '底分1分'}
    local maZhuangDes = {[1] = '买庄123分',[0] = ''}
    local fendingDes = {[1] = '不封顶', [2] = '封顶600胡', [3] = '封顶800胡'}
    local strDes = string.format('%s %s %s %s %s', jiangDes[jiang] or '', xiDes[xi] or '', difenDes[difen] or '', maZhuangDes[maizhuang] or '', fendingDes[fending] or '')
    return strDes
end

function TableLogic:OnGameMessage(scmd,smsg,Player)
     skynet.error("[tableframe]",scmd)
     self:OnGameMsg(scmd, smsg, Player)
end

function TableLogic:OnGameMsg(scmd, smsg, Player)
    local data = string.sub(smsg, 5)
    local act = self.DoMsgList[scmd]
    if act then 
       self:DoMsg(act, data, Player) 
    end
end

function TableLogic:DoMsg(act, smsg, Player)
    local seat = self:GetSeatByPlayer(Player)
    local chair = seat.chairAction
    if chair then 
        local reciever = self
        if act.Reciever then reciever = act.Reciever end
        if act.UnPackFormat == '' then 
            act.Func(reciever, chair, act.Type)
        else
            if act.Type then 
                act.Func(reciever, chair, act.Type, string.unpack(act.UnPackFormat, smsg))
            else 
				act.Func(reciever, chair, string.unpack(act.UnPackFormat, smsg))
            end
        end
    end
end

function TableLogic:OnSitDownSucess(seat)
    local GAME_ID = tonumber(skynet.getenv('game_id')) or 1001 
    skynet.error("self.PlayerNum = ",self.PlayerNum)
    local msg = string.pack(">I2>I2<I4<I4", 303, 2070, GAME_ID, self.PlayerNum)    --再告诉客户端几人麻将
    self:send_data(seat,msg)

    local chairAct = seat.chairAction
    chairAct.addr = seat.Player.nAgentAddr
    chairAct.PlayerId = seat.Player.nPlayerId
    self.chairAddr[chairAct.addr] = chairAct
end

function TableLogic:UserComeBack(seat)
    local GAME_ID = tonumber(skynet.getenv('game_id')) or 1001 
    local msg = string.pack(">I2>I2<I4<I4", 303, 2070, GAME_ID, self.PlayerNum)    --再告诉客户端几人麻将
    self:send_data(seat,msg)

    local chairAct = seat.chairAction
    chairAct.addr = seat.Player.nAgentAddr
    chairAct.PlayerId = seat.Player.nPlayerId
    self.chairAddr[chairAct.addr] = chairAct
end
 
function TableLogic:ConcluedGameLastRound()
    local dataBuf = string.pack('I2', nGameJuIndex)
    for i = 1, 20 do
        local scoreJu = self.GameScoreJu and self.GameScoreJu[i] or nil
        if scoreJu then
            dataBuf = dataBuf..string.pack('i2i2i2i2', (scoreJu[0] or 0), (scoreJu[1] or 0), (scoreJu[2] or 0), (scoreJu[3] or 0))
        else
            dataBuf = dataBuf..string.pack('I2I2I2I2', 0,0,0,0)
        end
    end
    skynet.error(string.format('ConcluedGameLastRound ju is %d', nGameJuIndex))
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_NT8JuGameOver, dataBuf)
    self.GameScoreJu = {}
    nGameJuIndex = 1
    return true
end

function TableLogic:OneJuOver()
	
end

function TableLogic:GetSeatCount()
	self.chairIndex = {1,2,3}
    return 3,self.chairIndex
end

function TableLogic:RegisterFun()
	self.DoMsgList = {}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_StandUpReq]       = {UnPackFormat = '',  Func = TableLogic.StandUp}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_OutCardReq]       = {UnPackFormat = 'B', Func = TableLogic.OnOutCard}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoAnGangReq]      = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_ANGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelAnGangReq]   = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_ANGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoJiaGangReq]     = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_JIAGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelJiaGangReq]  = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_JIAGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelJieGangReq]  = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_JIEGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelPengReq]     = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_PENG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoJieGangReq]     = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_JIEGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoPengReq]        = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_PENG}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoDuGangReq]      = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_DU}
    --self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_GoOnGameReq]      = {UnPackFormat = '',  Func = TableFrameSink.OnUserGoOnGameReq, Reciever = TableFrameSink}   --继续游戏
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoHuReq]          = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_HU}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CancelHuReq]      = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_HU}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoChiReq]         = {UnPackFormat = 'BBB', Func = TableLogic.DoActionReq,   Type = WIKTYPE.WIK_LINE}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelChiReq]      = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_LINE}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_FanJiangOrNot]    = {UnPackFormat = 'B',  Func = TableLogic.ProcFanJiangOrNot}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_LiaoLongOrNot]    = {UnPackFormat = 'B',  Func = TableLogic.ProcLiaoLongOrNot}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_MaiZhuangOrNot]   = {UnPackFormat = 'B',  Func = TableLogic.ProcMaiZhuangOrNot}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_ReportTingResp]   = {UnPackFormat = 'i2',  Func = TableLogic.ProcBaoTingOrNot}
    
    --TableLogic:RegisterFun()
    self.actFun = {}
    self.actFun[WIKTYPE.WIK_LINE]    = TableLogic.DoCommonActReq
    self.actFun[WIKTYPE.WIK_PENG]    = TableLogic.DoCommonActReq
    self.actFun[WIKTYPE.WIK_JIAGANG] = TableLogic.DoGangActReq
    self.actFun[WIKTYPE.WIK_JIEGANG] = TableLogic.DoGangActReq
    self.actFun[WIKTYPE.WIK_ANGANG]  = TableLogic.DoGangActReq
    --self.actFun[WIKTYPE.WIK_HU]      = TableLogic.DoHuReq
    self.actFun[WIKTYPE.WIK_DU] = TableLogic.DoGangActReq
end


function TableLogic:ProcBaoTingOrNot(chair, type)
    print('^^^^^^^^ chair baoting is ', chair.UserChairID, (type or -1))
    chair.DoneBaoTing = type
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UpdateBaoTingState, string.pack('i2b', chair.UserChairID, type))
    self.CouldBaoTingNum = self.CouldBaoTingNum - 1
    if self.CouldBaoTingNum == 0 then     --报听结束，开始接受act消息
        for chair in self:ChairIterator() do 
            chair:SendOperateHint()   
        end
    end
end

function TableLogic:ProcLiaoLongOrNot(chair, liao)
    skynet.error(string.format('recev liao is %0x', liao))
    self.LiaoLongRepeat = (self.LiaoLongRepeat or 0) + 1     --撂龙的次数
    if liao ~= 0 then    --选择了撂龙
        self:DoLiaoLong(chair, liao)
        self:AskLiaoLong(chair)    --看可不可以继续撂龙
    else 
        chair.DoneLiaoLong = true
        self:AskLiaoLong(self:GetNextChair(chair))
    end
end

function TableLogic:DoLiaoLong(chair, liao)   --发送撂龙的结果
    local msg = string.pack('bb', chair.UserChairID, liao)      --bb b bb
    local tabGetCard = {}
    local liaoItem = self.tabLiaoLongGetCardNum[liao]  
    if liaoItem then
        for i = 1, (liaoItem.newGetCard or 0) do
            local card = self:DispatchCardFromRep(chair)       --补到百搭时不用替换，后面的过程会替换 
            tabGetCard[#tabGetCard + 1] = card
            chair:AddHandCard(card)
        end
        liaoItem.Done = true
        chair.tabLiaoLong[#chair.tabLiaoLong + 1] = liao
        local index = MjLogic:ValToIndex(liao)
        chair.tabCbCardIndex[index] = chair.tabCbCardIndex[index] - liaoItem.cardInHand
        msg = msg..string.pack('bbb', liaoItem.newGetCard or 0, tabGetCard[1] or 0, tabGetCard[2] or 0)  --补牌的张数，值
        skynet.error(string.format('DoLiaoLong , getnum is %d, getPai is %0x, %0x', liaoItem.newGetCard or 0, tabGetCard[1] or 0, tabGetCard[2] or 0))
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_LiaoLongRet, msg)
    end
end

function TableLogic:DoGangActReq(type, chair, centerCard)      --杠
    if type == WIKTYPE.WIK_JIAGANG then   --可以抢杠胡
        if self:CheckQiangGangHu(type, chair, centerCard) then return end
    end
    local provider = chair:DoActionReq(chair.DoMsgList[type], centerCard) 
    if provider then
        if type == WIKTYPE.WIK_JIEGANG then self:SetNextUser() end  --接杠
        self:DoActionCmd(type, chair, provider, centerCard)
        if centerCard ~= self.tabJiang[1] and centerCard ~= self.tabJiang[2] then  --笃不需要摸牌
            self:DispatchCard(chair, type)
        else
            chair:OnDispatchCard(0, self.LeftCardCount, true)    --笃完之后可能有暗杠，因为笃不摸牌，所以在这里判断
        end
    end
end

function TableLogic:MakeReadyTable()   
    self.CurUserId = 0
    self.LeftCardCount = TABLECONST.PAI_TOTAL
    self.HasDoHu = false
    self.HasConclude = false
    self.tabGang = {}
    self.FanJiangRepeat = 0
    self.PermitOutCard = false
    self.ProcMaiZhuangNum = 0
    self.DoneLLCount = 0
    self.tabLiaoLongGetCardNum = {}
    self.tabJiang = {}
    self.tabCurGetCard = {}   -- 当前摸牌了的牌值和人Id，不一定是正在出牌的人，因为有碰杠
    
    function ClearChairInTable(chair)    --只清空在Table用到chair数据
        chair.DoneLiaoLong = false
        chair.tabXiPai = {}
        chair.MaiZhuang = nil
        chair.GameState = GameState.ready
    end

    for chair in self:ChairIterator() do
        chair:MakeReadyChair(self)
        ClearChairInTable(chair)
    end
end

function TableLogic:OnPlayerOfflineBack(seat)
    --local chair = self:UserIdToChair(seat.m_wChairId)
    --chair.addr = seatPlayer.nAgentAddr                          --重新获得地址
    --self.chairAddr[chair.addr] = chair
    self:SendMeOfflineBackData(seat.Player, seat.m_wChairId)
end

function TableLogic:OnEventGameStart()
	self:MakeReadyTable()
    for chair in self:ChairIterator() do
       chair.GameState = GameState.play 
       chair:SetConfig(TableConfig)
    end
	self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_GameStart)
	if TableConfig.MaiZhuang then 
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_AskMaiZhuang) 
    else 
        self:MjLogicBegin()
    end
end

function TableLogic:OneJuOver()
    self.TableObj.m_wCurJu = self.TableObj.m_wCurJu + 1 
end

function TableLogic:StandUp(chair)
	local msg = string.pack('<I2', chair.UserChairID)
	self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_PlayerQuit, msg)
end

function TableLogic:DoActionReq(chair, type, centerCard, cardBef, cardAft)
    if type == WIKTYPE.WIK_HU then 
        chair.DoneHu = true
        -- if self:WaitForOtherActs(chair, type, centerCard, cardBef, cardAft) then    --点胡了,但是因为有其他玩家也胡,暂时胡不了
        -- else 
            -- self:DoHuReq(chair, centerCard)    --只有一家胡
        -- end
        self:DoHuReq(chair, centerCard)    --只有一家胡
    else 
        if self.actFun[type] then self.actFun[type](self, type, chair, centerCard, cardBef, cardAft) end
    end    
end

function TableLogic:DoHuReq(chair, getCardData)
    if self.HasDoHu then return end    --防止重复
    local bHu, huType, fan, provider = chair:DoHu(getCardData)
    if bHu then
        self:DoHuCmd(chair, provider, getCardData, huType, fan)
    end
    self.HasDoHu = true
end

function TableLogic:DoHuCmd(chair, provider, getCardData, huType, fan)
    local bZiMo = false
    if provider and provider ~= -1 then 
        self:UserIdToChair(provider).DianPao = true
    else bZiMo = true end
    fan = fan or 0
    --fan = fan | self:GetFanWaiFan(chair)
    self.HuCardData = getCardData
    local bufData = string.pack('<I2B<IIIIIIIIII', chair.UserChairID, huType, fan&FANWAIFAN.QINGYISE, fan&FANWAIFAN.GANGPAO, 
    fan&FANWAIFAN.GANGHUA, fan&FANWAIFAN.HAIDIPAO, fan&FANWAIFAN.HAIDIHU, fan&FANWAIFAN.QIANGGANGHU, 
    fan&FANWAIFAN.QUANQIUREN, fan&FANWAIFAN.TIANHU, fan&FANWAIFAN.DIHU, fan&FANWAIFAN.ZIYISE)

    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_HuPai, bufData)
    chair.tabHuResult = {ProviderId = provider, HuCardData = getCardData, HuType = huType, Fan = fan}
    
    local HuData = {HuId = chair.UserChairID, HuCardData = getCardData, HuType = huType, ZiMo = bZiMo, Fan = fan}
    self:GameOver(HuData)
end

function TableLogic:DoCommonActReq(type, chair, centerCard, cardBef, cardAft)      --吃,碰
    local provider = chair:DoActionReq(chair.DoMsgList[type], centerCard, cardBef, cardAft)
    if provider then 
        self:SetNextUser()
        self:DoActionCmd(type, chair, provider, centerCard, cardBef, cardAft)
    end
end


function TableLogic:DoActionCmd(type, chair, provider, centerCard, cardBef, cardAft)
    local wUserChairId = chair.UserChairID
    self.CurUserId = chair.UserChairID
    local dataBuf = ''
    
    function FillGangFen(type)
        local dataBuf = string.pack('<I2B', wUserChairId, centerCard)
        for i = 1, TABLECONST.FULL_PLAYER do
            local chairIn = self.chairAct[i]
            if chairIn then 
                if type == WIKTYPE.WIK_ANGANG then 
                    if chairIn.UserChairID == chair.UserChairID then dataBuf = dataBuf..string.pack('i', self:GetPerGangFen(type) * (self.PlayerNum - 1))
                    else dataBuf = dataBuf..string.pack('i', self:GetPerGangFen(type) * -1) end
                elseif type == WIKTYPE.WIK_JIAGANG then 
                    if chairIn.UserChairID == chair.UserChairID then dataBuf = dataBuf..string.pack('i', self:GetPerGangFen(type))
                    elseif chairIn.UserChairID == provider then dataBuf = dataBuf..string.pack('i', self:GetPerGangFen(type) * -1) 
                    else dataBuf = dataBuf..string.pack('i', 0) end
                end
            else 
                dataBuf = dataBuf..string.pack('i', 0) 
            end
        end
        return dataBuf
    end
    
    if type == WIKTYPE.WIK_PENG then 
        dataBuf = dataBuf..string.pack('<I2B<I2<I2', wUserChairId, centerCard, provider, wUserChairId)
        dataBuf = dataBuf..chair.tabUserAction:GetPackString()
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoPengOk, dataBuf)
        
    elseif type == WIKTYPE.WIK_LINE then 
        dataBuf = dataBuf..string.pack('<I2B<I2<I2BB', wUserChairId, centerCard, provider, wUserChairId, cardBef, cardAft)
        chair.tabUserAction:Reset()
        dataBuf = dataBuf..chair.tabUserAction:GetPackString()
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoChiOk, dataBuf)
        
    elseif type == WIKTYPE.WIK_JIEGANG then 
        local bufData = string.pack('<I2B<I2IIII', wUserChairId, centerCard, provider, 0,0,0,0)
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoJieGangOk, bufData)
        
    elseif type == WIKTYPE.WIK_JIAGANG then 
        --local dataBuf = FillGangFen(type)
        local bufData = string.pack('<I2B<IIII', wUserChairId, centerCard, 0,0,0,0)
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoJiaGangOk, bufData)
        
    elseif type == WIKTYPE.WIK_ANGANG then 
        --local dataBuf = FillGangFen(type)
        local bufData = string.pack('<I2B<IIII', wUserChairId, centerCard, 0,0,0,0)
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoAnGangOk, bufData)
    elseif type == WIKTYPE.WIK_DU then
        local bufData = string.pack('<I2B<IIII', wUserChairId, centerCard, 0,0,0,0)
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoDuGangOk, bufData)
    end
    
end

function TableLogic:WaitForOtherActs(chairAct, type, centerCard, cardBef, cardAft, provider)
    local otherActNum = self:OtherChairsHasMoreAct(chairAct, type)
    if otherActNum > 0 then
        chairAct:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_WaitingForAnotherHu)
        chairAct.tabToDo = {}
        chairAct.tabToDo.Num = otherActNum
        chairAct.tabToDo.Func = chairAct.DoDelayAction
        chairAct.tabToDo.tabParam = {type, {centerCard, cardBef, cardAft}, provider}
        chairAct.OperateBit = 0
        return true 
    end
    return false
end

function TableLogic:OtherChairsHasMoreAct(chairAct, type)
    local oneAct = 0
    for otherChair in self:ChairIterator() do
        if otherChair.UserChairID ~= chairAct.UserChairID then
            otherChair.OperateBit = otherChair.OperateBit or 0
            if type*otherChair.OperateBit > 0 and otherChair.OperateBit >= type then
                oneAct = oneAct + 1
            end
        end
    end
    return oneAct
end

function TableLogic:CheckQiangGangHu(type, chair, centerCard)
    local chCouldHu 
    for ch in self:ChairIterator() do
        local couldHu = ch:CanHu(centerCard, chair.UserChairID)
        if couldHu then 
            ch.OperateBit = ch.OperateBit|WIKTYPE.WIK_HU
            if not chCouldHu then chCouldHu = ch end
        end
    end
    
    if self:WaitForOtherActs(chair, type, centerCard) then   
        if chCouldHu then chCouldHu:SendOperateHint() end
        return true
    end
    return false
end

function TableLogic:CancelActionReq(chair, type)
    if chair:CancelActionReq(type) then      --取消成功,可能会重复发送消息
        chair.OperateBit = 0
        
        for otherChair in self:ChairIterator() do        --取消时其他玩家可能还有操作未被执行,例如有玩家1碰,玩家2胡,2取消
            if otherChair.UserChairID ~= chair.UserChairID then
                if otherChair.tabToDo and otherChair.tabToDo.tabParam then 
                    if not otherChair.tabToDo.Num then otherChair.tabToDo.Num = 1 end   
                    otherChair.tabToDo.Num = otherChair.tabToDo.Num - 1 
                    local param = otherChair.tabToDo.tabParam    --type, tabCardData, provider
                    if otherChair.tabToDo.Num == 0 or self:OtherChairsHasMoreAct(otherChair, param[1]) == 0 then  --例如抢杠时，有两个人可以胡，只有这两个人都取消后才能继续杠 
                        otherChair.tabToDo.Func(otherChair, param[1], param[2], param[3])
                        otherChair.tabToDo = nil
                        return
                    end
                    return
                end 
            end            
        end
       
        for otherChair in self:ChairIterator() do    --其他玩家没有同样的动作(一般是胡)要处理,有多响时要检测
            if otherChair.UserChairID ~= chair.UserChairID and #otherChair.tabUserAction > 0 then
                for i = 1, #otherChair.tabUserAction do
                    if otherChair.tabUserAction[i].Type == type then    --玩家取消胡，如果下一家可以胡，则让他显示
                        otherChair:SendOperateHint()
                        return 
                    end
                end
            end
        end
        
        for chair in self:ChairIterator() do       --其他玩家有动作,比如取消点炮,可能下个玩家有吃(因为有胡,吃时,吃没有显示出来)
            if #chair.tabUserAction > 0 then 
                self.CurUserId = self.LastOutCardId
                chair:SendOperateHint()
                return 
            end
        end
           
        if self.CurUserId ~= chair.UserChairID then   --取消暗杠,加杠,自摸胡不需要转移到其他玩家
            self:SetNextUser()
            self:DispatchCard()
        end
    end
end

function TableLogic:ProcMaiZhuangOrNot(chair, maiOrNot)   --每个玩家开始发牌前都会先发送是否买庄的消息
    skynet.error(string.format('Id %d maiOrNot: %d', chair.UserChairID, maiOrNot or -1))
    if maiOrNot == 1 then
        chair.MaiZhuang = 1
        skynet.error(string.format('chair Id %d select maizhuang', chair.UserChairID))
    else
        skynet.error(string.format('chair Id %d donot select maizhuang', chair.UserChairID))
        chair.MaiZhuang = 0
    end
    self.ProcMaiZhuangNum = self.ProcMaiZhuangNum + 1
    if self.ProcMaiZhuangNum == self.PlayerNum then 
        self:MjLogicBegin()
    end
end

function TableLogic:MjLogicBegin()
    local numPai = TABLECONST.PAI_TOTAL
    MjLogic:Init(TABLECONST.PAI_TOTAL)
    MjLogic:randCard(1)
    self:RandomFromConfig(MjLogic.table_RepertoryCard)
    nGameJuIndex = nGameJuIndex + 1
    self:StartFaPai(nGameJuIndex)
    
end

function TableLogic:RandomFromConfig(tab_RandCard)
    local fapai_server = skynet.getenv('fapai_server')
    local fapai_file = skynet.getenv('fapai_file')
    local Tables 
    if fapai_server and fapai_file then 
        local httpc = require "http.httpc"
        local status, body =  httpc.get(fapai_server, fapai_file, {})
        skynet.error('get fapai from ', (fapai_server or ''), (fapai_file or ''), 'status is', status)
        local TablesFun = load(body)
        if TablesFun then Tables = TablesFun() end
        if not Tables then skynet.error('parse FaPai.lua error') return end 
    else    
        local logicPath = skynet.getenv('gamelogic_path')
        if not logicPath then return end
        skynet.error('logicPath is'..logicPath)
        local fileFaPai = io.open(logicPath..'FaPai.lua',rb)
        if fileFaPai then fileFaPai:close() 
        else skynet.error('no fapai file!!!') return end
        Tables = require("FaPai")
    end

    local Table
    for chair in self:ChairIterator() do
        if Tables[chair.PlayerId] ~= nil then
            Table = Tables[chair.PlayerId]
            break
        end
    end
    if not Table then skynet.error('no Id of the plays!!!') return end     --没有该玩家的脚本
    if not Table.Enable then return end     --没有开启
    if not Table.endPai then Table.endPai = {} end
    local cuRepertoryCard = {}
    for i = 1, TABLECONST.PAI_TOTAL do
        cuRepertoryCard[i] = 0
    end
    local cbLeftCardCount = TABLECONST.PAI_TOTAL
    local pai = {Table.pai_1, Table.pai_2, Table.pai_3, Table.pai_4, Table.pai_5}
    if self.PlayerNum == 2 then 
        pai = {Table.pai_1, Table.pai_2, Table.pai_5}
    elseif self.PlayerNum == 3 then 
        pai = {Table.pai_1, Table.pai_2, Table.pai_3, Table.pai_5}
    end
    local iStart = 0
    for k = 1, #pai do
         for i = 1, TABLECONST.MAX_COUNT - 1 do
            cuRepertoryCard[cbLeftCardCount] = pai[k][i]
            if not cuRepertoryCard[cbLeftCardCount] then cuRepertoryCard[cbLeftCardCount] = 0 end
            cbLeftCardCount = cbLeftCardCount - 1
            iStart = iStart + 1
        end
    end
    for i = 1, #Table.endPai do
        cuRepertoryCard[i] = Table.endPai[i]
    end
    cbLeftCardCount = TABLECONST.PAI_TOTAL
    for i = TABLECONST.PAI_TOTAL, 1, -1 do
        if i > (cbLeftCardCount - iStart) and cuRepertoryCard[i] > 0 then 
            for j = 1, cbLeftCardCount do
                if tab_RandCard[j] == cuRepertoryCard[i] then 
                    tab_RandCard[cbLeftCardCount], tab_RandCard[j] = tab_RandCard[j], tab_RandCard[cbLeftCardCount]
                    cbLeftCardCount = cbLeftCardCount - 1
                    cuRepertoryCard[i] = 0  
                    break
                end
            end
        else break
        end
    end
    
    cbLeftCardCount = TABLECONST.PAI_TOTAL
    local iEnd = #Table.endPai
    for i = 1, TABLECONST.PAI_TOTAL do
        if i < iEnd and cuRepertoryCard[i] > 0 then 
            for j = i, cbLeftCardCount - iStart do
                if tab_RandCard[j] == cuRepertoryCard[i] then
                    tab_RandCard[i], tab_RandCard[j] = tab_RandCard[j], tab_RandCard[i]
                    cuRepertoryCard[i] = 0
                    break
                end
            end
        else break
        end
    end
    return tab_RandCard
end

function TableLogic:StartFaPai(wJu)
    local tab_RandCard = MjLogic.table_RepertoryCard
    self.cardRepertory = tab_RandCard
	self.LeftCardCount = TABLECONST.PAI_TOTAL
    for i = 1, self.PlayerNum do
        local chair = self:GetChair(i)      
        for j = 1, TABLECONST.NUM_HANDFULL - 1 do       
            local val = tab_RandCard[self.LeftCardCount]
            chair.tabCardVal[#chair.tabCardVal + 1] = val
            chair:AddHandCard(val)
            self.LeftCardCount = self.LeftCardCount - 1
        end
    end
    
    for chair in self:ChairIterator() do
        chair:StartFaPai(wJu)
        chair:UpdataTingData()
	end
    self.CurUserId = self.Banker
    self:DispatchCard(self:UserIdToChair(self.CurUserId))
end

function TableLogic:ChairIterator(wCurId)
    local i = 0
    return function()
        i = i + 1
        if i <= self.PlayerNum then 
            local chair = self:GetChair(i)
            if wCurId and wCurId == chair.UserChairID then return nil end    --忽略当前玩家
            if chair and chair.addr then return chair
            else return nil end    --退出后地址就为nil
        end
    end
end

function TableLogic:GetChair(chairIndex)  --chairIndex 是以1开始的,而不是1
    return self.chairAct[self.chairIndex[chairIndex]]
end


function TableLogic:DispatchCard(chair, type)    --摸牌
    if self:CheckLiuJu() then 
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_ChouZhang)
        return 
    end
    if chair == nil then 
        chair = self:UserIdToChair(self.CurUserId)
        --chair = self:UserIdToChair(self.CurUserId) 
    end
    local getCard
    if self.PermitOutCard then    --允许出牌时才判断替换百搭
        self:ReplaceXiPaiInHand(chair)
        getCard = self:DispatchCardFromRep(chair)
        if getCard > 0x40 and self.LeftCardCount > 0 then   --最后一张是喜牌时不算喜牌了
            getCard = self:SkipXiPai(getCard, chair)
        end
    else
        getCard = self:DispatchCardFromRep(chair)
    end
    
    self.tabCurGetCard.getCard = getCard   --玩家当前的牌,用于断线重连
    self.tabCurGetCard.id = chair.UserChairID
    chair:OnDispatchCard(getCard, self.LeftCardCount, self.PermitOutCard)
    self.CurUserId = chair.UserChairID
    self:DispatchCardToOthers(chair)
    
    if not self.FanJiangRepeat or self.FanJiangRepeat == 0 then
        self:AskFanJian(chair, 'DispatchCard')
    end
end

function TableLogic:CheckLiuJu()
    local Tables = {}
    local logicPath = skynet.getenv('gamelogic_path')
    if logicPath then 
        local fileFaPai = io.open(logicPath..'FaPai.lua',rb)
        if fileFaPai then fileFaPai:close() 
            Tables = require("FaPai")
        else skynet.error('no fapai file!!!') end
    end

    local Table = {}
    for chair in self:ChairIterator() do
        if Tables[chair.PlayerId] ~= nil then
            Table = Tables[chair.PlayerId]
            break
        end
    end
    
    local nLeft = 0
    if Table.leftCard and Table.leftCard > 0 then nLeft = TABLECONST.PAI_TOTAL - Table.leftCard - (TABLECONST.MAX_COUNT - 1) * self.PlayerNum end
    if self.LeftCardCount <= nLeft then 
        self.LiuJu = true
        local HuData = {LiuJu = true}
        self:GameOver(HuData)
        --skynet.call(self.ItableSrv, "lua", "ConcludeGame", self.TableObj, HuData)
        return true
    end
    return false
end

function TableLogic:AskFanJian(chair, type)              --询问是否翻将
    local msg = string.pack('b', chair.UserChairID)
    --chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_AskFanJiang)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_AskFanJiang, msg)
    print('In AskFanJian!!!!!!!!!!!! , id is ', chair.UserChairID, 'type is ', type or '')
    self.CurAskFanJian = chair
end

function TableLogic:DispatchCardToOthers(chair, getCard)    --发牌给别人
    local wUserChairId = chair.UserChairID
    for chair in self:ChairIterator() do
        if chair.UserChairID ~= wUserChairId then 
            chair:OthersCardToMe(wUserChairId, self.LeftCardCount)
        end
    end
end

function TableLogic:SkipXiPai(val, chair)    --跳过摸喜牌
    if val > 0x40 then 
        chair.tabXiPai = chair.tabXiPai or {}
        chair.HasDispatchXiPai = true
        local getCard
        local tabXiPai = {val}
        chair.tabXiPai[#chair.tabXiPai + 1] = val
        while true do
            getCard = self:DispatchCardFromRep(chair)
            if getCard < 0x41 then break
            else 
                chair.tabXiPai[#chair.tabXiPai + 1] = getCard
                tabXiPai[#tabXiPai + 1] = getCard 
            end
        end
        local msgXiPai = string.pack("I2b", chair.UserChairID, #tabXiPai)    --用户Id，喜牌数量 
        msgXiPai = msgXiPai..string.pack('bbbbb', tabXiPai[1] or 0,tabXiPai[2] or 0,tabXiPai[3] or 0,tabXiPai[4] or 0,tabXiPai[5] or 0)
        msgXiPai = msgXiPai..string.pack('bbbbb', 0,0,0,0,0)   --新的牌为0，因为还是会去dispatch   --新的牌
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_ReplaceXiPai, msgXiPai)
        skynet.error(string.format('SkipXiPai, num is %d, val is %0x', #tabXiPai, getCard))
        return getCard
    end
end

function TableLogic:ReplaceXiPaiInHand(chair)
    local tabXiPai = self:CheckXiPaiInHand(chair)
    if tabXiPai and #tabXiPai > 0 then   --判断在手的牌是否有喜牌
        skynet.error('xipai in hand, num is ', #tabXiPai, 'Id is ', chair.UserChairID)
        self:ReplaceXiPai(chair, tabXiPai)
    end
end

function TableLogic:CheckXiPaiInHand(chair)
    local tabXiPai = {}
    for i = 1, 5 do
        if chair.tabCbCardIndex[MjLogic:ValToIndex(0x40 + i)] > 0 then 
            tabXiPai[#tabXiPai + 1] = 0x40 + i
        end
    end
    if #tabXiPai > 0 then chair.HasDispatchXiPai = true end
    return tabXiPai
end

function TableLogic:ReplaceXiPai(chair, tabXiPai)
    local msgXiPai = string.pack("I2b", chair.UserChairID, #tabXiPai)    --用户Id，喜牌数量 
    local nCnt = #tabXiPai
    chair.tabXiPai = chair.tabXiPai or {}
    for i = 1, 5 do
        msgXiPai = msgXiPai..string.pack('b', tabXiPai[i] or 0)     --要替换的喜牌
        chair.tabCbCardIndex[MjLogic:ValToIndex(0x40 + i)] = 0
        if tabXiPai[i] and tabXiPai[i] > 0 then
            chair.tabXiPai[#chair.tabXiPai + 1] = tabXiPai[i]
        end
    end
    while nCnt > 0 do
        local getCard = self:DispatchCardFromRep(chair)
        if getCard < 0x41 then 
            nCnt = nCnt - 1 
            msgXiPai = msgXiPai..string.pack('b', getCard)         --新的牌
            chair:AddHandCard(getCard)
        end
    end
    for i = 1, 5 - #tabXiPai do    --填充0
        msgXiPai = msgXiPai..string.pack('b', 0)
    end

    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_ReplaceXiPai, msgXiPai)
    skynet.error('send msgXiPai len is ', string.len(msgXiPai))
end

function TableLogic:DispatchCardFromRep(chair, type)
    local getCard = self.cardRepertory[self.LeftCardCount]
    self.LeftCardCount = self.LeftCardCount - 1
    skynet.error(string.format('id %d get card is %0x!!!!!!!!!',chair.UserChairID, getCard))
    if type ~= 'FangJiang' then chair.LastGetCard = getCard end   --翻将时摸的牌
    return getCard
end

function TableLogic:UserIdToChair(wUserChairId)    --userId 是以0开始的,而不是1
    local chairIndex = wUserChairId + 1
    return self.chairAct[chairIndex]
end

function TableLogic:ProcFanJiangOrNot(chair, fan)  --处理是否翻将
    skynet.error(string.format('Id %d fanjiang or not :%d', chair.UserChairID, fan or -1))
    self.FanJiangRepeat = (self.FanJiangRepeat or 0) + 1     --没有翻将的次数
    if fan == 1 then 
        for i = 1, TableConfig.FanJiangNum do
             local jiang = self:DispatchCardFromRep(chair, 'FangJiang')
             self.tabJiang[#self.tabJiang + 1] = jiang
        end
        local msg = string.pack('bbbb', chair.UserChairID, TableConfig.FanJiangNum, self.tabJiang[1] or 0, self.tabJiang[2] or 0)  --翻将的值
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_FanJiangRet, msg)
        skynet.error(string.format('Id %d fanjiang val is :%0x', chair.UserChairID, self.tabJiang[1] or 255), self.tabJiang[2] or "")
        
        self:StatusForLiaoLong(self:UserIdToChair(self.Banker))    --翻将之后庄家撂龙
    else
        if self.FanJiangRepeat == 3 then  --流局
            skynet.error("no one fangjiang, do liuju!!!!!!!!!!!!")
            local HuData = {FangjiangLiuJu = true, HuCardData = 0, HuType = 0, ZiMo = false, LiuJu = true}
            --skynet.call(self.ItableSrv, "lua", "ConcludeGame", self.TableObj, HuData)
            self:GameOver(HuData)
        else   
            chair = self:GetNextChair(chair)
            self:AskFanJian(chair, 'else')
        end
    end
end

function TableLogic:StatusForLiaoLong(chair)
     if self.tabJiang and #self.tabJiang > 0 and not chair.DoneLiaoLong then   --还没有撂龙
        skynet.error('in dispatch card, wait liao long!!!!!!')
        self:AskLiaoLong(chair)
    end
end

function TableLogic:AskLiaoLong(chair)                --询问是否撂龙
    skynet.error(string.format('In AskLiaoLong userId : %d', chair.UserChairID))
    if chair.DoneLiaoLong then        --已经完成了撂过程，不能撂也算
        for ch in self:ChairIterator() do
            if ch.DoneLiaoLong then self.DoneLLCount = self.DoneLLCount + 1 end
        end
        if self.DoneLLCount == 3 then 
            skynet.error('All Done LiaoLong!!!!!!!!!!!!!!!!!')
            self:NotfiyFirstOutCardMsg()   --可以开始出牌了
        end
        return false 
    end
    local tabLiao = self:CanLiaoLong(chair)
    if tabLiao and #tabLiao > 0 then 
        local msg = string.pack('bb', chair.UserChairID, #tabLiao)
        for i = 1, 7 do
            msg = msg..string.pack('b', tabLiao[i] or 0)
        end
        chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_AskLiaoLong, msg)
        --self:BroadCastData(CMD.Sub_GameSvrToClient_TableModle_AskLiaoLong, msg)
        skynet.error('send ask for liaolong, chairId is ', chair.UserChairID)
    else    --牌型不能撂龙
        chair.DoneLiaoLong = true
        self:AskLiaoLong(self:GetNextChair(chair))
        return false
    end
    return true
end
--此三个功能放进平台处理
function TableLogic:WantFaceReq(chair, which)
    local msg = string.pack('I2I4', chair.UserChairID, which or 0)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserWantFaceResult, msg)
end

function TableLogic:WantShortVoiceReq(chair, which)
    local msg = string.pack('I2I4', chair.UserChairID, which or 0)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserWantVoiceResult, msg)
end

function TableLogic:SendTextReq(chair, id, content)
    local msg = string.pack('I4c256', id, content)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_SendTxt, msg)
end
-----------------------------------
function TableLogic:CanLiaoLong(chair)
    local tabLiao = {}
    local nXiPai = 0
    for i = 1, PAICONST.MAX_INDEX do
        if chair.tabCbCardIndex[i] == 4 then      --手牌有4张
            local val = MjLogic:IndexToVal(i)
            tabLiao[#tabLiao + 1] = val
            self.tabLiaoLongGetCardNum[val] = {newGetCard = 1, cardInHand = 4, id = chair.UserChairID}    --补一张牌
        end
        if i >= 31 and chair.tabCbCardIndex[i] > 0 then nXiPai = nXiPai + 1 end   --百搭+1
    end
    
    --一个将，三个手牌
    local jiangIndex1 = MjLogic:ValToIndex(self.tabJiang[1] or 0)
    if jiangIndex1 > 0 and chair.tabCbCardIndex[jiangIndex1] == 3 then
        tabLiao[#tabLiao + 1] = self.tabJiang[1] 
        self.tabLiaoLongGetCardNum[self.tabJiang[1]] = {newGetCard = 0, cardInHand = 3, id = chair.UserChairID}
    end
    local jiangIndex2 = MjLogic:ValToIndex(self.tabJiang[2] or 0)
    if jiangIndex2 > 0 and chair.tabCbCardIndex[jiangIndex2] == 3 then
        tabLiao[#tabLiao + 1] = self.tabJiang[2] 
        self.tabLiaoLongGetCardNum[self.tabJiang[2]] = {newGetCard = 0, cardInHand = 3, id = chair.UserChairID}
    end
    --两个将，三个手牌
    if TableConfig.FanJiangNum == 2 then
        if jiangIndex1 == jiangIndex2 and chair.tabCbCardIndex[jiangIndex1] == 2 then   --双将时，手牌2个一样补两张
            tabLiao[#tabLiao + 1] = self.tabJiang[2]
            self.tabLiaoLongGetCardNum[val] = {newGetCard = 2, cardInHand = 2, id = chair.UserChairID}   --补2张牌
        end
    end
    
    if jiangIndex1 > 0x40 or jiangIndex2 > 0x40 then    --将里面有百搭
        local temp = {[true] = 1, [false] = 0}
        nXiPai = nXiPai + temp[jiangIndex1 > 0x40]
        nXiPai = nXiPai + temp[jiangIndex2 > 0x40]
    end
    if nXiPai == 5 then
        tabLiao[#tabLiao + 1] = 0x40 
        local numXiPaiInHand = 5 - (temp[jiangIndex1 > 0x40] + temp[jiangIndex2 > 0x40])
        self.tabLiaoLongGetCardNum[0x40] = {newGetCard = numXiPaiInHand, cardInHand = numXiPaiInHand, id = chair.UserChairID}
    end
    skynet.error(string.format('cal chairId %d liao long : %0x, %0x', chair.UserChairID, tabLiao[1] or 0, tabLiao[2] or 0))
    return tabLiao --{0x01, 0x02}
end

function TableLogic:NotfiyFirstOutCardMsg()
    local chair = self:UserIdToChair(self.Banker)

    for ch in self:ChairIterator() do
        self:ReplaceXiPaiInHand(ch)
    end
        
    self.PermitOutCard = true
    skynet.error('NotfiyFirstOutCardMsg!!!!!! ', chair.UserChairID)
    local msg = string.pack('b', self.Banker)
    --self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_FirstOutCard, msg)
    
    function CouldBaoTing(chair)
        return #chair.tabTingCardData ~= 0 and #chair.tabTingCardData.val ~= 0
    end
    self.CouldBaoTingNum = 0
    local msgBt = ''
    for chair in self:ChairIterator() do
        if chair.UserChairID == self.Banker then
            msgBt = msgBt..string.pack('b', 0)
        else
            local temp = {[true] = 1, [false] = 0}
            local bt = CouldBaoTing(chair)
            chair.CouldBaoTing = bt
            self.CouldBaoTingNum = self.CouldBaoTingNum + temp[bt]
            msgBt = msgBt..string.pack('b', temp[bt]) 
        end
    end
    
    local b1,b2,b3 = string.unpack('bbb', msgBt)
    print('&&&&&&&&&&& b1,b2,b3 is ', b1,b2,b3)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_FirstOutCard, msg..msgBt)
    
    chair:CanGang(0, WIKTYPE.WIK_ANGANG)
    chair:CanHu(chair.LastGetCard)
    
    local dispatchMsg = string.pack("I2B", chair.UserChairID, 0)
    dispatchMsg = dispatchMsg..chair.tabUserAction:GetPackString()
    dispatchMsg = dispatchMsg..string.pack("I2", self.LeftCardCount)
    chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_DispatchCardToMe, dispatchMsg)   --只能这样发送消息来提示暗杠
end

function TableLogic:GetNextChair(chair)      --返回下一个有效的玩家
    local idNext = self:GetNextChairId(chair.UserChairID)
    return self:UserIdToChair(idNext)
end

function TableLogic:GetNextChairId(wCurId)   --返回下一个玩家的ID,用在判断吃
    wCurId = (wCurId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER;
	if self.PlayerNum == 2 then
		if wCurId == 1 or wCurId == 3 then
			wCurId = (wCurId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER;
		end
	elseif self.PlayerNum == 3 then
		if wCurId == 3 then
			wCurId = (wCurId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER;
		end
	end
	return wCurId;
end

function TableLogic:UpdataTingData(chair)
    chair:UpdataTingData()
end

function TableLogic:OnOutCard(chair, cbCardData)
    local wUserChairId = chair.UserChairID
    self.CurOutCard = cbCardData
    chair:OnOutCard(cbCardData)
    chair.LianGang = 0
    self.LastOutCardId = wUserChairId
    self.tabCurGetCard = {}
    self.CurUserId = wUserChairId
    self:UpdataTingData(chair)
    local tabCouldHu = {}
    local hasPengOrGang = false
    
    local dataToSend = string.pack('<I2B', wUserChairId, cbCardData)
    for chair in self:ChairIterator() do 
        chair.OperateBit = 0
        local couldHu, couldPengOrGang = false, false
        if chair.UserChairID ~= wUserChairId then
            couldHu = chair:CanHu(cbCardData, wUserChairId)
            couldPengOrGang = chair:CanPeng(cbCardData, wUserChairId)
            if couldPengOrGang then chair.OperateBit = chair.OperateBit|WIKTYPE.WIK_PENG end
            local bGang = chair:CanGang(cbCardData, WIKTYPE.WIK_JIEGANG, wUserChairId)
            if bGang then chair.OperateBit = chair.OperateBit|WIKTYPE.WIK_JIEGANG end
            couldPengOrGang = bGang or couldPengOrGang
            if couldHu then table.insert(tabCouldHu, chair.UserChairID) chair.OperateBit = chair.OperateBit|WIKTYPE.WIK_HU end
            
        end
        if couldPengOrGang then hasPengOrGang = true end
        local hp = 0
        if couldPengOrGang then hp = 1 end

        chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_UserOutCard, dataToSend)
    end
    
    for chair in self:ChairIterator() do   
        if chair.UserChairID ~= wUserChairId then
            if (chair.OperateBit&(WIKTYPE.WIK_PENG|WIKTYPE.WIK_HU)) > 0 then
                if self.CouldBaoTingNum == 0 then   --没有在报听状态
                    chair:SendOperateHint() 
                    if (chair.OperateBit & WIKTYPE.WIK_HU ~= 0) then   --因为没有一炮多响，有一个可以胡的就不同时发给另一个
                        break
                    end
                end
            end
        end
    end
    
    if (not hasPengOrGang) and (#tabCouldHu == 0) then 
        self:SetNextUser()
        self:DispatchCard()
    end
end

function TableLogic:SetNextUser()
    self.CurUserId = (self.CurUserId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER
    self:ValidCurrentUserChairId()
end

function TableLogic:ValidCurrentUserChairId()       --修正2,3人麻将下一个玩家的问题
    if self.PlayerNum == 2  then
        if self.CurUserId == 1 or self.CurUserId == 3 then
            self.CurUserId = (self.CurUserId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER
        end
    elseif self.PlayerNum == 3 then
        if self.CurUserId == 3 then
            self.CurUserId = (self.CurUserId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER
        end
    end
    return self.CurUserId
end


function TableLogic:ConcludeGame(huData)
    if self.HasConclude then return end

    if huData.FangjiangLiuJu then
        self.room.m_nBanker = self.Banker
        print('TableObj.m_nBanker is ', self.room.m_nBanker)  
        --skynet.call(self.ItableSrv, "lua", "ConcludeGameFriend", self.TableObj)--注意
        self.room.ConcludeGameFriend()
        local huPaiResult = {CardData=0, bHu={false,false,false,false},gameScoreJu={0,0,0,0},huShuJu={0,0,0,0},standCard={{},{},{},{}},huPaiMsg={"","","",""}}
        local result = HuPaiResult:New(huPaiResult)
        for chair in self:ChairIterator() do
            if chair then
                local standCard = chair:GetStandCard()
                local chairIndex = chair.UserChairID + 1
                result.standCard[chairIndex] = standCard or {}
            end    
        end
        local dataBuf = result:GetPackString()
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_NTHuPaiResult, dataBuf)
        self.HasConclude = true
        
        return false
    end

    local bZiMo = huData.ZiMo or false
    if not huData.LiuJu then    --没有流局,买马且自摸才买马选项下自摸
        --self.Banker = self:GetNewBanker(huData)     --设置新的庄家
    else
        self.LiuJuNum = (self.LiuJuNum or 0) + 1
    end
    

    for chair in self:ChairIterator() do
        chair:ConcludeGame(huData)
    end
    

    self:CalScore(huData)   --计算出每个玩家的分
   
    local huPaiResult = {CardData=0, bHu={false,false,false,false},gameScoreJu={0,0,0,0},huShuJu={0,0,0,0},standCard={{},{},{},{}},huPaiMsg={"","","",""}}
    local result = HuPaiResult:New(huPaiResult)
    result.CardData = huData.HuCardData
    for chair in self:ChairIterator() do
        if chair then
            local chairIndex = chair.UserChairID + 1
            result.bHu[chairIndex] = chair.DoneHu
            result.gameScoreJu[chairIndex] = chair.GameScoreJu or 0
            print("chairIndex = "..chairIndex.." GameScoreJu"..result.gameScoreJu[chairIndex])
            result.huShuJu[chairIndex] = chair.HuShu or 0
            local standCard = chair:GetStandCard()
            result.standCard[chairIndex] = chair.standCard or {}
            result.huPaiMsg[chairIndex] = chair.ResultMsg or ""
        end
    end
    local dataBuf = result:GetPackString()
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_NTHuPaiResult, dataBuf)
    skynet.error('Broadcast HuPaiResult!!!!!!!!!!!')
    self.HasConclude = true
    self:UpdataChairs(huData)
    for chair in self:ChairIterator() do
        local chair_obj = self:GetSeatByChairId(chair.UserChairID)
        chair_obj.Player.nScore = (chair_obj.Player.nScore or 0) + chair.GameScoreJu
    end
    --skynet.call(self.ItableSrv, "lua", "ConcludeGameFriend", self.TableObj)
    self.room.ConcludeGameFriend()
    function ClearChairData()
        for chair in self:ChairIterator() do
            chair.GameScoreJu = 0
            chair.standCard = {}
            chair.ResultMsg = ''
            chair.DoneHu = false
            chair.tabHuResult = {}
        end
        self.LiuJu = false
    end
    ClearChairData()

    return false
end

function TableLogic:CalScore(huData)   --计算得分
    function ClearScore()
        for chair in self:ChairIterator() do
            chair.GameScoreJu = 0
            chair.HuShu = 0
        end
    end
    ClearScore()
    for chair in self:ChairIterator() do
        chair.HuShu = chair:CalTotalHuShu(huData)    --计算每个人的总胡数chair.HuShu
        local limits = {[1] = chair.HuShu, [2] = 600, [3] = 800}
        if chair.HuShu > limits[TableConfig.FengDing] then 
            chair.HuShu = limits[TableConfig.FengDing]
        end
        print('&&&&&&id, huShuJu is ', chair.UserChairID, ' ', chair.HuShu)
    end
    -- for chair in self:ChairIterator() do
        -- chair.GameScoreJu = chairHuShu[chair.UserChairID] * 3 - totalHuShu   --(x-y + x-z) => 3x-(x+y+z)
    -- end
    --要乘以买庄倍数
    self.GameScoreJu = self.GameScoreJu or {}
    self.GameScoreJu[nGameJuIndex] = {}
    for i = 0, self.PlayerNum - 1 do
        local chair1 = self:UserIdToChair(i)
        local chair2 = self:UserIdToChair((i + 1) % self.PlayerNum)
        local chair3 = self:UserIdToChair((i + 2) % self.PlayerNum)
        chair1.GameScoreJu = (chair1.HuShu - chair2.HuShu) * ((chair1.MaiZhuang or 0) + (chair2.MaiZhuang or 0) + 1) + (chair1.HuShu - chair3.HuShu) * ((chair1.MaiZhuang or 0) + (chair3.MaiZhuang or 0) + 1) 
        self.GameScoreJu[nGameJuIndex][chair1.UserChairID] = chair1.GameScoreJu
        skynet.error(string.format('ju Id %d, chair Id %d scoreJu is %d, %d_%d_%d_%d_%d_%d', nGameJuIndex, chair1.UserChairID, chair1.GameScoreJu,chair1.HuShu,chair2.HuShu,chair3.HuShu,(chair1.MaiZhuang or -1),(chair2.MaiZhuang or -1),(chair3.MaiZhuang or -1)))
    end
end

function TableLogic:GetSeatByChairId(chairId)
    for _,seat in pairs(self.m_pChairs) do
        if seat.m_wChairId == chairId then
            return seat
        end
    end
    return nil
end

function TableLogic:UpdataChairs(huData)     --数据填充到平台上,累积每局
    self.room.m_nBanker = self.Banker
    for chair in self:ChairIterator() do
        local chairObj = self:GetSeatByChairId(chair.UserChairID)
        if not chairObj then print('chairObj is not ok '..chair.UserChairID) end
        chairObj.nScores = chairObj.nScores + chair.GameScoreJu
        chairObj.nMingGang = chairObj.nMingGang + (chair.nMingGang or 0)
        chairObj.nAnGang = chairObj.nAnGang + (chair.nAnGang or 0)
        if chair.UserChairID == huData.HuId then 
            chairObj.m_nHuPaiTotal = (chairObj.m_nHuPaiTotal or 0) + 1
        end
        if chair.UserChairID == huData.ProviderId then 
            chairObj.nDiaoPao = (chairObj.nDiaoPao or 0) + 1
        end
    end
end


function TableLogic:SendMeOfflineBackData(Player, wUserChairId) 
    skynet.error('SendMeOfflineBackData Id:', wUserChairId, 'CurUserId is ', self.CurUserId)
    local chair = self:UserIdToChair(wUserChairId)
    if self.HasConclude then    --结算时断线
        print('SendMeOfflineBackData in ConcludeGame---------------------------')
        chair.GameState = GameState.ready   --这时候就准备
        self:CheckStartGame()
        return
    end
    
    local bufData = ''
    bufData = bufData..string.pack('I2I2', self.Banker, self.CurUserId)  --庄家和当前用户
    --bufData = bufData..chair.tabUserAction:GetPackString()
    local myGetCard = 0
    local standCard = chair:GetStandCard()
    if self.CurUserId == chair.UserChairID and #standCard % 3 == 2 then myGetCard = self.tabCurGetCard.getCard or 0 end  --当前玩家,且牌未满
    bufData = bufData..string.pack('BB', self.LeftCardCount, myGetCard or 0)  --剩余数量和刚才摸的牌,如果他不是当前玩家,就为0
    -- if #standCard % 3 == 2 then   --牌满的情况下要去掉 
        -- local len = #standCard  
        -- for i = 1, len do
            -- if standCard[i] == self.tabCurGetCard then table.remove(standCard, i) end
        -- end
    -- end
    
    if self.CurUserId == chair.UserChairID and self.tabCurGetCard.id == chair.UserChairID then 
        local ind = MjLogic:ValToIndex(self.tabCurGetCard.getCard)
        chair.tabCbCardIndex[ind] = chair.tabCbCardIndex[ind] - 1   --先剪掉
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do            --WORD        StandCardCount[GAME_PLAYER];
        local chair = self.chairAct[i]
        if chair then 
            if chair.UserChairID == wUserChairId then 
                bufData = bufData..string.pack('I2', #standCard)
            else 
                bufData = bufData..string.pack('I2', #chair:GetStandCard())
            end
        else bufData = bufData..string.pack('I2', 0) end 
    end
    
    bufData = bufData..chair:SendMeOfflineBackData('standCard')

    for i = 1, TABLECONST.FULL_PLAYER do
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..string.pack('I2', #chair.tabWeaveItem)   
        else bufData = bufData..string.pack('I2', 0) end
    end

    for i = 1, TABLECONST.FULL_PLAYER do        --tagWeaveItem    arrWeaveItem[GAME_PLAYER][MaxWeaveCount];
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..chair:SendMeOfflineBackData('weaveItem', wUserChairId)   
        else bufData = bufData..BufTool.WriteOffset(6 * TABLECONST.MAXWEAVCOUNT) end 
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..string.pack('I2', #(chair.tabCbOutCard or {}))
        else bufData = bufData..string.pack('I2', 0) end
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..chair:SendMeOfflineBackData('outCard')   
        else bufData = bufData..BufTool.WriteOffset(TABLECONST.MAXOUTCARDCOUNT) end
    end

    local lenTing = 0
    if chair.tabTingCardData and chair.tabTingCardData.val then lenTing = #chair.tabTingCardData.val end    
    bufData = bufData..string.pack('B', lenTing)
    bufData = bufData..chair:SendMeOfflineBackData('tingData')
    
    for i = 1, TABLECONST.FULL_PLAYER do    --喜牌
        local chair = self.chairAct[i]
        if chair then
            for i = 1, 5 do
                bufData = bufData..string.char(chair.tabXiPai[i] or 0)
            end
        else bufData = bufData..BufTool.WriteOffset(5) end
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do        --撂龙    arrWeaveItem[GAME_PLAYER][MaxWeaveCount];
        local chair = self.chairAct[i]
        if chair then 
            local nPerLiaolong = 0
            local ch = ''
            for k, v in pairs(self.tabLiaoLongGetCardNum) do
                if v.id == chair.UserChairID and v.Done then
                    nPerLiaolong = nPerLiaolong + 1
                    ch = ch..string.char(k)
                end
            end
            bufData = bufData..ch
            bufData = bufData..BufTool.WriteOffset(TABLECONST.MAXWEAVCOUNT - nPerLiaolong)
            if chair.UserChairID == wUserChairId then
                print('LiaoLong SendMeOfflineBackData Id:', wUserChairId, 'nPerLiaolong is ', nPerLiaolong)
            end
        else 
            bufData = bufData..BufTool.WriteOffset(TABLECONST.MAXWEAVCOUNT) 
        end 
    end
    --print('jiangpai SendMeOfflineBackData Id:', wUserChairId, 'FanJiangNum is ', Config.FanJiangNum, 'val is ', self.tabJiang[1] or 0, self.tabJiang[2] or 0)
    bufData = bufData..string.pack('bbb', TableConfig.FanJiangNum, self.tabJiang[1] or 0, self.tabJiang[2] or 0)    --将牌
    chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_NTOfflineBackData, bufData)
    
    if self.PermitOutCard then    --允许出牌
        local msg = string.pack('b', self.Banker)
        if chair.CouldBaoTing and chair.DoneBaoTing == -1 then    ---通知是否可以报听
            for i = 0, 2 do
                if  i == wUserChairId then
                    msg = msg..string.pack('b', 1)
                else
                    msg = msg..string.pack('b', 0)
                end
            end
        end
        chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_FirstOutCard, msg)
        for chair in self:ChairIterator() do        --报听之后要告诉状态
            if chair.DoneBaoTing > 0 then
                chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_UpdateBaoTingState, string.pack('i2b', chair.UserChairID, chair.DoneBaoTing))
            end                
        end
        if self.CurUserId ~= chair.UserChairID and type(chair.tabUserAction) == 'table' and #chair.tabUserAction > 0 then   --可以碰杠时断线
            chair:SendOperateHint()
            local dataToSend = string.pack('<I2B', self.LastOutCardId, self.CurOutCard)
            chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_UserOutCard, dataToSend)
        end
    else
        if self.ProcMaiZhuangNum ~= self.PlayerNum then    --买庄状态
            if not chair.MaiZhuang then 
                if TableConfig.MaiZhuang then chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_AskMaiZhuang) end
            end
        end
        if not self.tabJiang[1] and self.CurAskFanJian then self:AskFanJian(self.CurAskFanJian, 'DX') end  ----翻将状态
        self:StatusForLiaoLong(chair)
    end
    
    if self.CurUserId == chair.UserChairID then 
        print('SendMeOfflineBackData DispatchCard Agin , id', chair.UserChairID, 'cur card is ', self.tabCurGetCard.getCard)
        if self.tabCurGetCard.id == chair.UserChairID then
            chair:OnDispatchCard(self.tabCurGetCard.getCard, self.LeftCardCount, self.PermitOutCard)
        end
        self.CurUserId = chair.UserChairID
    end
    
end

function TableLogic:IsPlaying()
    return self.room.m_nGameState ~= 2
end

return TableLogic